/* pjd.h - defini��o da interface de servi�os do protocolo de janela
 * deslizante. Essa interface deve ser usada por protocolos da camada
 * superior que desejem usar o protocolo para se comunicar de forma
 * confi�vel pela rede.
 */


#include <string>
#include <iostream>
#include <time.h>


class pjdConnection{
public:
	int pjdId;
public:
	static int nextPjdId;
	int lastBlockSent;
	int lastBlockAck;
	int lastBlock;

	void printNode(int);
	pjdConnection(int, int, int);
	pjdConnection();
	int searchKey();

};


class windowPackage{
public:
	static int dataMaxSize;
	int totalBlocks;
	int blockNumber;
	bool inUse;
	//CRC
	int op;
	char* data;
	int dataLen; //Em caso de ser um ACK - este campo representará o numero de bytes restante no buffer de entrada
	int connection;
	int messageId;
	int pjdId;
	int errCode;
	bool ack;
	struct timeval start, finish;

public:
	windowPackage(int, int, int, char*);
	windowPackage();
	void printNode(int);
	int searchKey(){ return messageId; }
	int mountPackageToSend(char**);
	static bool verifyPackage(char*, int);
	static windowPackage* mountPackageReceived(char *, int);
	void printPackageForm();

};



char& divideMsg(char*, int, int&);

void error(std::string);

class list{
public:
	class windowNode{
	public:
		windowNode* next;
		windowNode* previous;
		bool hasNext;
		windowPackage data;

		windowNode(windowPackage);
		windowPackage* getData();
	};
	class connectionNode{
	public:
		connectionNode* next;
		connectionNode* previous;
		bool hasNext;
		pjdConnection data;

		connectionNode(pjdConnection);
		pjdConnection* getData();
	};
	const void* firstNode;
	const void* lastNode;
	int listSize;
	int maxSize;
public:
	bool insertNode(windowPackage);
	bool insertNode(pjdConnection);
	bool removeFirstNode();//window
	bool removeFirstNode(int);//pjd
	void deleteNode(int key, int flag);
	bool exists(int, int);
	bool isEmpty();
	bool isFull();
	int getSize();

	const void* getFirstNode();
	windowPackage** searchNode(int, int);//window
	pjdConnection* searchNode(int);//pjd
	void printList();//window
	void printList(int);//pjd

	list();
	list(int);
};

#ifndef _PJD_H_
#define _PJD_H_

/* A maior mensagem que pode ser enviada usando-se o protocolo PJD � de
 * 2 KB (dados entregues a PJD). Na pr�tica, o tamanho pode ser diferente
 * disso, dependendo da tecnologia de rede local adotada e nos testes a
 * interface ser� configurada de forma a variar esse valor, logo ele s�
 * deve ser usado como uma refer�ncia para a aloca��o de espa�o limite
 * para os buffers que ser�o usados.
 */
#define MAX_PJD_MSG (2*1024)

/* pjd_mtu retorna o valor real do maior pacote aceito por PJD para
 * transmiss�o (isto �, a parte de dados de um pacote PJD). Deve ser
 * chamada ap�s a inicializa��o do protocolo, que deve ser feita com a
 * fun��o pjd_init, a seguir. Em caso de erro, retorna um valor negativo.
 */
int pjd_mtu(void);

/* pjd_init � usado para quaisquer inicializa��es que sejam necess�rias
 * para o protocolo de janela deslizante. O argumento indica o no. do
 * porto que ser� usado pelo protocolo para se identificar sobre UDP na
 * m�quina corrente. Esse n�mero deve ser maior que 2048 e menor que
 * 65536, ou zero, caso o sistema possa escolher esse n�mero
 * aleatoriamente. A fun��o retorna o n�mero do porto escolhido em caso
 * de sucesso ou um valor menor que zero em caso de erro.
 *
 * Aqui ocorrerá a inicialização das threads
 */
int pjd_init( int pjd_port );

/* pjd_passivo faz a abertura passiva de uma conex�o. N�o h� nenhum
 * par�metro nesse caso, pois a abertura ser� feita sobre o porto UDP
 * indicado na inicializa��o. Se bem sucedido, retorna um inteiro que
 * representar�, para a camada pjd, a conex�o aberta. Esse par�metro
 * ser� usado no envio e recep��o de mensagens para identificar a
 * conex�o (pjd deve ser implementado para permitir a abertura de
 * diferentes conex�es usando um mesmo porto UDP).
 */
int pjd_passivo( void );

/* pjd_ativo faz a parte ativa da abertura de uma conex�o. Os par�metros
 * s�o um string contendo o nome ou o endere�o IP da m�quina onde a parte
 * passiva da conex�o est� sendo executada e o n�mero do porto UDP usado
 * pelo programa que fez a abertura passiva. Da mesma forma que
 * pjd_passivo, o valor de retorno identifica a conex�o pjd nessa
 * m�quina.
 */
int pjd_ativo( char* other_host, int other_port );

/* pjd_send envia a mensagem contida no buffer identificado por
 * msg_buffer, com msg_len bytes, atrav�s da conex�o identificada por
 * pjdd. Este �ltimo valor � o identificador retornado por uma das
 * fun��es de abertura de conex�o (ativa/passiva). � fun��o de pjd
 * conferir se o tamanho da mensagem cabe no MTU definido durante a
 * execu��o. Retorna zero em caso de sucesso e um valor negativo em
 * qualquer condi��o de erro, inclusive o fechamento da conex�o do outro
 * lado.
 * A fun��o retorna imediatamente se houver espa�o nos buffers de PJD
 * para armazenar a mensagem para envio, ou pode ficar travada at� que
 * esse espa�o se torne dispon�vel (devido a quest�es de controle de
 * fluxo).
 */
int pjd_send(int pjdd, char* msg_buffer, int msg_len);

/* Fun��o sim�trica da anterior para recebimento de mensagens. Da mesma
 * forma, o tamanho do buffer deve ser conferido na chamada. Caso a
 * mensagem recebida seja maior que o buffer fornecido o restante da
 * mensagem (que extrapole o tamanho do buffer) ser� descartado. Em caso
 * de sucesso a fun��o retorna com o tamanho real da mensagem recebida
 * (que pode ser menor que o buffer fornecido). Se a conex�o tiver sido
 * fechada pelo outro lado, retorna zero e em caso de erro retorna
 * um valor negativo.
 * A fun��o bloqueia at� que uma mensagem v�lida para entrega
 * seja recebida por PJD ou a conex�o tenha sido fechada.
 */
int pjd_recv(int pjdd, char* msg_buffer, int msg_len);

/* pjd_close fecha a conex�o. Ao retornar, garante que todos os dados
 * enviados pela conex�o j� foram entregues. Pode ser chamada por
 * qualquer lado da conex�o. Se for chamada pelo receptor e houverem
 * dados na janela de recep��o ainda n�o lidos pela camada superior eles
 * s�o descartados (mas isso n�o constitui erro para o transmissor).
 * � um erro para ambos os lados chamar um recv/send depois de uma
 * conex�o ter sido fechada.
 *
 * Encerramento das threads
 */
int pjd_close( int pjdd );


#endif /* _PJD_H_ */
